home *** CD-ROM | disk | FTP | other *** search
/ PC User 2003 January / Disc 1 / PCU0103CD1.iso / entertn / demos / files / aomtrial.exe / AOM / AI / SCN18P9.XS < prev    next >
Encoding:
Text File  |  2002-09-10  |  20.8 KB  |  575 lines

  1. //==============================================================================
  2. // Scn18p9: AI Scenario Script for scenario 18 player 9
  3. //==============================================================================
  4. /*
  5.    AI owner:  Dave Leary
  6.    Scenario owner: Joe "The Golem" Gillum
  7.  
  8.     This AI does some basic training and then transports small groups to attack
  9.     the player (4 axemen, 4 spearmen, and 1 scarab).  Pacing of the attacks is
  10.     controlled by the scenario designer.
  11. */
  12. //==============================================================================
  13. // Need scn lib for some stuff here.
  14. include "scn lib.xs";
  15.  
  16.  
  17. // Functions to check to see what's hanging around the point.
  18. int checkForMilitary(vector point = vector(-1,-1,-1))
  19. {
  20.    return(getUnassignedUnitCount(point, 30.0, cMyID, cUnitTypeLogicalTypeLandMilitary));
  21. }
  22.  
  23.  
  24. //==============================================================================
  25. // Set Town Location
  26. //==============================================================================
  27. void setTownLocation(void)
  28. {
  29.    //Look for the "Town Location" marker.
  30.    kbSetTownLocation(kbGetBlockPosition("9954"));
  31. }
  32.  
  33. //==============================================================================
  34. // miscStartup
  35. //==============================================================================
  36. void miscStartup(void)
  37. {
  38.     // Difficulty Level check.
  39.     int difflevel=-1;        
  40.     difflevel=aiGetWorldDifficulty();
  41.  
  42.    //Startup message(s).
  43.    aiEcho("");
  44.    aiEcho("");
  45.    aiEcho("Scn18P9 AI Start, filename='"+cFilename+"'.");
  46.     aiEcho("Difficulty Level="+difflevel+".");
  47.    //Spit out the map size.
  48.    aiEcho("  Map size is ("+kbGetMapXSize()+", "+kbGetMapZSize()+").");
  49.    //Cheat like a bastard.  Once only, though.
  50.    kbLookAtAllUnitsOnMap();
  51.    //Calculate some areas.
  52.    kbAreaCalculate(1200.0);
  53.    //Set our town location.
  54.    setTownLocation();
  55.     //Reset random seed
  56.     aiRandSetSeed();
  57.    //Allocate all resources to the root escrow.
  58.    kbEscrowAllocateCurrentResources();
  59.     
  60.     // Large AI attack response distance for this player
  61.     aiSetAttackResponseDistance(50.0);
  62. }
  63.  
  64. //==============================================================================
  65. //==============================================================================
  66. // Attack stuff.
  67. //==============================================================================
  68. //==============================================================================
  69. //Shared variables.
  70.  
  71. int attackerUnitTypeIDSoldier1=cUnitTypeAxeman;
  72. int attackerUnitTypeIDSoldier2=cUnitTypeSpearman;
  73. int attackerUnitTypeIDMyth=cUnitTypeScarab;
  74. int attackerUnitTypeIDTransport=cUnitTypePirateShip;
  75.  
  76. int attackPlan1ID=-1;
  77.  
  78. //=========================================================================================
  79. // Kidd's cool configQuery function: used to create attack routes, etc.  Oooh, lovin' that!
  80. //=========================================================================================
  81. /*
  82. bool configQuery( int queryID = -1, int unitType = -1, int action = -1, int state = -1, int player = -1, vector center = vector(-1,-1,-1), bool sort = false, float radius = -1 )
  83. {
  84.    if ( queryID == -1)
  85.    {
  86.       return(false);
  87.    }
  88.  
  89.    if (player != -1)
  90.       kbUnitQuerySetPlayerID(queryID, player);
  91.    
  92.    if (unitType != -1)
  93.       kbUnitQuerySetUnitType(queryID, unitType);
  94.  
  95.    if (action != -1)
  96.       kbUnitQuerySetActionType(queryID, action);
  97.  
  98.    if (state != -1)
  99.       kbUnitQuerySetState(queryID, state);
  100.  
  101.    if (center != vector(-1,-1,-1))
  102.    {
  103.       kbUnitQuerySetPosition(queryID, center);
  104.       if (sort == true)
  105.          kbUnitQuerySetAscendingSort(queryID, true);
  106.       if (radius != -1)
  107.          kbUnitQuerySetMaximumDistance(queryID, radius);
  108.    }
  109.    return(true);
  110. }
  111. */
  112.  
  113. //=====================================================================================
  114. // Attack Launcher.  This is called from the scenario with an AI Func effect
  115. //=====================================================================================
  116. void attackLauncher(int whichAttack = -1)
  117. {
  118.     int transportPlanID=aiPlanCreate("Transport Group", cPlanTransport);
  119.     // "whichTransport" adds a specific transport to the plans.  Victory conditions, chats, etc.
  120.     // are tied to the concept of the main transport getting whacked.
  121.     int whichTransport=-1;
  122.  
  123.     // Difficulty Level check.
  124.     int difflevel=-1;        
  125.     difflevel=aiGetWorldDifficulty();
  126.  
  127.     vector gatherPoint=kbGetBlockPosition("9952");
  128.     vector targetPoint=kbGetBlockPosition("9953");
  129.     
  130.     if (transportPlanID >= 0)
  131.    {
  132.         aiEcho("*** ATTACK LAUNCHER SENDING TRANSPORT ***");
  133.         
  134.         aiPlanAddUnitType(transportPlanID, cUnitTypePirateShip, 1, 1, 1);
  135.         aiPlanAddUnitType(transportPlanID, cUnitTypeAxeman, 0, 4, 4);
  136.         aiPlanAddUnitType(transportPlanID, cUnitTypeSpearman, 0, 4, 4);
  137.         aiPlanAddUnitType(transportPlanID, cUnitTypeScarab, 0, 1, 1);
  138.         aiPlanSetVariableInt(transportPlanID, cTransportPlanTransportTypeID, 0, cUnitTypePirateShip);
  139.  
  140.         /*
  141.         // Different composition depending on which attack.
  142.         switch(whichAttack)
  143.         {    
  144.             case 0:
  145.           {
  146.                 aiPlanAddUnitType(transportPlanID, cUnitTypePirateShip, 1, 1, 1);
  147.                 aiPlanAddUnitType(transportPlanID, cUnitTypeAxeman, 0, 4, 4);
  148.                 aiPlanAddUnitType(transportPlanID, cUnitTypeSpearman, 0, 4, 4);
  149.                 aiPlanAddUnitType(transportPlanID, cUnitTypeScarab, 0, 1, 1);
  150.                 aiPlanSetVariableInt(transportPlanID, cTransportPlanTransportTypeID, 0, cUnitTypePirateShip);
  151.                 break;
  152.             }
  153.  
  154.             case 1:
  155.             {
  156.                 whichTransport = kbGetBlockID("2637");
  157.                 gatherPoint=kbGetBlockPosition("2640");
  158.                 targetPoint=kbGetBlockPosition("2643");
  159.  
  160.                 aiPlanAddUnitType(transportPlanID, cUnitTypePirateShip, 1, 1, 1);
  161.                 aiPlanAddUnitType(transportPlanID, cUnitTypeAxeman, 5, 5, 5);
  162.                 aiPlanSetVariableInt(transportPlanID, cTransportPlanTransportTypeID, 0, cUnitTypePirateShip);
  163.                 aiPlanSetVariableInt(transportPlanID, cTransportPlanTransportID, 0, whichTransport);
  164.                 break;
  165.             }
  166.  
  167.             case 2:
  168.             {
  169.                 whichTransport = kbGetBlockID("2633");
  170.                 gatherPoint=kbGetBlockPosition("2658");
  171.                 targetPoint=kbGetBlockPosition("2641");
  172.  
  173.                 aiPlanAddUnitType(transportPlanID, cUnitTypePirateShip, 1, 1, 1);
  174.                 aiPlanAddUnitType(transportPlanID, cUnitTypeAxeman, 6, 6, 6);
  175.                 
  176.                 if ( difflevel > 0 )
  177.                 {
  178.                     aiPlanAddUnitType(transportPlanID, cUnitTypeSlinger, 2, 2, 2);
  179.                 }
  180.  
  181.                 aiPlanSetVariableInt(transportPlanID, cTransportPlanTransportTypeID, 0, cUnitTypePirateShip);
  182.                 aiPlanSetVariableInt(transportPlanID, cTransportPlanTransportID, 0, whichTransport);
  183.                 break;
  184.             }
  185.  
  186.             case 3:
  187.             {
  188.                 whichTransport = kbGetBlockID("2788");
  189.                 gatherPoint=kbGetBlockPosition("2640");
  190.                 targetPoint=kbGetBlockPosition("2641");
  191.  
  192.                 aiPlanAddUnitType(transportPlanID, cUnitTypePirateShip, 1, 1, 1);
  193.                 aiPlanAddUnitType(transportPlanID, cUnitTypeSlinger, 6, 6, 6);
  194.                 
  195.                 if ( difflevel > 0 )
  196.                 {
  197.                     aiPlanAddUnitType(transportPlanID, cUnitTypeAnubite, 2, 2, 2);
  198.                 }
  199.                 
  200.                 aiPlanSetVariableInt(transportPlanID, cTransportPlanTransportTypeID, 0, cUnitTypePirateShip);
  201.                 aiPlanSetVariableInt(transportPlanID, cTransportPlanTransportID, 0, whichTransport);
  202.                 break;
  203.             }
  204.  
  205.             case 4:
  206.             {
  207.                 whichTransport = kbGetBlockID("2634");
  208.                 gatherPoint=kbGetBlockPosition("2639");
  209.                 targetPoint=kbGetBlockPosition("2785");
  210.  
  211.                 aiPlanAddUnitType(transportPlanID, cUnitTypePirateShip, 1, 1, 1);
  212.                 aiPlanAddUnitType(transportPlanID, cUnitTypeAxeman, 7, 7, 7);
  213.                 aiPlanAddUnitType(transportPlanID, cUnitTypeScorpionMan, 1, 1, 1);
  214.                 aiPlanSetVariableInt(transportPlanID, cTransportPlanTransportTypeID, 0, cUnitTypePirateShip);
  215.                 aiPlanSetVariableInt(transportPlanID, cTransportPlanTransportID, 0, whichTransport);
  216.                 break;
  217.             }
  218.  
  219.         }
  220.         */
  221.  
  222.         aiPlanSetVariableBool(transportPlanID, cTransportPlanMaximizeXportMovement, 0, true);
  223.         
  224.         aiPlanSetVariableVector(transportPlanID, cTransportPlanGatherPoint, 0, gatherPoint);
  225.       aiPlanSetVariableVector(transportPlanID, cTransportPlanTargetPoint, 0, targetPoint);
  226.  
  227.         aiPlanSetDesiredPriority(transportPlanID, 75);
  228.  
  229.         // Don't return when finished.
  230.         aiPlanSetVariableBool(transportPlanID, cTransportPlanReturnWhenDone, 0, false);
  231.         
  232.         aiPlanAddUnit(transportPlanID, whichTransport);
  233.       aiPlanSetActive(transportPlanID);
  234.    }
  235. }
  236.  
  237. //==============================================================================
  238. // initAttack: Creates attack routes, etc.
  239. //==============================================================================
  240. /*
  241. void initAttack(int playerID=-1)
  242. {
  243.    //Destroy all previous attacks (if this isn't the player we're already attacking.
  244.    if (playerID != attackPlayerID)
  245.    {
  246.       //Reset the attack player ID.
  247.       attackPlayerID=-1;
  248.       //Destroy any previous attack plan.
  249.       aiPlanDestroy(attackPlan1ID);
  250.       attackPlan1ID=-1;
  251.       aiPlanDestroy(attackPlan2ID);
  252.       attackPlan2ID=-1;
  253.   
  254.       //Destroy our previous attack paths.
  255.       kbPathDestroy(attackPath1ID);
  256.       attackPath1ID=-1;
  257.       kbPathDestroy(attackPath2ID);
  258.       attackPath2ID=-1;
  259.  
  260.       //Destroy our previous attack routes.
  261.       attackRoute1ID=-1;
  262.       attackRoute2ID=-1;
  263.  
  264.       //Reset the number of attacks.
  265.       numberAttacks=0;
  266.    }
  267.  
  268.    //Save the player to attack.
  269.    attackPlayerID=playerID;
  270.  
  271.    vector gatherPoint=kbGetBlockPosition("3989");
  272.        
  273.     //Setup attack path 1 - go left
  274.    attackPath1ID=kbPathCreate("Attack Path 1");
  275.    kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("3990"));
  276.     kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("3991"));
  277.     kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("3992"));
  278.    //Create attack route 1.
  279.    attackRoute1ID=kbCreateAttackRouteWithPath("Attack Route 1", gatherPoint, kbGetBlockPosition("3995"));
  280.    
  281.     if (attackRoute1ID >= 0)
  282.       kbAttackRouteAddPath(attackRoute1ID, attackPath1ID);
  283.  
  284.    //Setup attack path 2 - go right
  285.    attackPath2ID=kbPathCreate("Attack Path 2");
  286.    kbPathAddWaypoint(attackPath2ID, kbGetBlockPosition("3990"));
  287.     kbPathAddWaypoint(attackPath2ID, kbGetBlockPosition("3991"));
  288.     kbPathAddWaypoint(attackPath2ID, kbGetBlockPosition("3993"));
  289.     kbPathAddWaypoint(attackPath2ID, kbGetBlockPosition("3994"));
  290.    //Create attack route 2.
  291.    attackRoute2ID=kbCreateAttackRouteWithPath("Attack Route 2", gatherPoint, kbGetBlockPosition("3995"));
  292.    
  293.     if (attackRoute2ID >= 0)
  294.       kbAttackRouteAddPath(attackRoute2ID, attackPath2ID);
  295. }
  296. */
  297.  
  298. //==============================================================================
  299. // setupAttack
  300. //==============================================================================
  301. /*
  302. bool setupAttack(int playerID=-1)
  303. {
  304.     int randomPath=aiRandInt(2);
  305.    
  306.     //Info.
  307.     aiEcho("Attacking Player "+playerID+".");
  308.  
  309.    //If the player to attack doesn't match, init the attack.
  310.    if (attackPlayerID != playerID)
  311.    {
  312.       initAttack(playerID);
  313.       if (attackPlayerID < 0)
  314.          return(false);
  315.    }
  316.  
  317.    //Create an attack plan.
  318.    int newAttackPlanID=aiPlanCreate("Attack Player"+attackPlayerID+" Attempt"+numberAttacks, cPlanAttack);
  319.    if (newAttackPlanID < 0)
  320.       return(false);
  321.  
  322.    //Target player (required).  This must work.
  323.    if (aiPlanSetVariableInt(newAttackPlanID, cAttackPlanPlayerID, 0, attackPlayerID) == false)
  324.       return(false);
  325.  
  326.    //Gather point.
  327.     vector gatherPoint=kbGetBlockPosition("3989");
  328.  
  329.     //Set the target type.  This must work.
  330.    if (aiPlanSetNumberVariableValues(newAttackPlanID, cAttackPlanTargetTypeID, 2, true) == false)
  331.       return(false);
  332.  
  333.    //Unit types to attack.
  334.    aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 0, cUnitTypeUnit);
  335.     aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 1, cUnitTypeBuilding);
  336.  
  337.    //Attack route.
  338.    if (randomPath == 0)
  339.     {
  340.       aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRouteID, 0, attackRoute1ID);
  341.     }
  342.    else
  343.     {
  344.       aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRouteID, 0, attackRoute2ID);
  345.     }
  346.  
  347.    //Set the gather point and gather point distance.
  348.    aiPlanSetVariableVector(newAttackPlanID, cAttackPlanGatherPoint, 0, gatherPoint);
  349.    aiPlanSetVariableFloat(newAttackPlanID, cAttackPlanGatherDistance, 0, 10.0);
  350.  
  351.    //Set up the attack route usage pattern.
  352.    aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRoutePattern, 0, cAttackPlanAttackRoutePatternRandom);
  353.    
  354.     //Add the unit types to the plan.
  355.    aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID1, attackMinimumGroupSize, attackMaximumGroupSize, attackMaximumGroupSize);
  356.     
  357.    //Set the initial position.
  358.    aiPlanSetInitialPosition(newAttackPlanID, gatherPoint);
  359.    //Plan requires all need units to work (can be false).
  360.    aiPlanSetRequiresAllNeedUnits(newAttackPlanID, true);
  361.    //Activate the plan.
  362.    aiPlanSetActive(newAttackPlanID);
  363.  
  364.    //Now, save the attack plan ID appropriately.
  365.    aiPlanSetOrphan(attackPlan1ID, true);
  366.    attackPlan1ID=newAttackPlanID;
  367.  
  368.    //Increment our overall number of attacks.
  369.    numberAttacks++;
  370. }
  371. */
  372.  
  373. //==============================================================================
  374. // Attack Generator 1 - Axemen and friends
  375. //==============================================================================
  376. /*
  377. rule attackGenerator1
  378.    minInterval 75
  379.    inactive
  380.    group AttackRules
  381.    runImmediately
  382. {
  383.    //See how many "idle" attack plans we have.  Don't create any more if we have
  384.    //idle plans.
  385.    int numberIdleAttackPlans=aiGetNumberIdlePlans(cPlanAttack);
  386.  
  387.    if (numberIdleAttackPlans > 0)
  388.       return;
  389.  
  390.    //If we have enough unassigned military units, create a new attack plan.
  391.    int numberAvailableUnits=aiNumberUnassignedUnits(attackerUnitTypeID1);
  392.    aiEcho("There are "+numberAvailableUnits+" axemen available for a new attack.");
  393.    
  394.     if (numberAvailableUnits >= attackMinimumGroupSize)
  395.         setupAttack(1);
  396. }
  397. */
  398.  
  399.  
  400. //==============================================================================
  401. // Attack enablers - enable attacks after initial timers expire
  402. //==============================================================================
  403. /*
  404. // Axemen
  405. rule attack1Enabler
  406.    minInterval 240
  407.    active
  408.    group AttackRules
  409. {
  410.    xsEnableRule("attackGenerator1");
  411.    xsDisableSelf();
  412. }
  413. */
  414.  
  415. //==============================================================================
  416. // Tech Researching Rules - medium axemen, medium slingers, medium spearmen
  417. //==============================================================================
  418. /*
  419. rule researchMediumAxemen
  420.    minInterval 600
  421.    active
  422. {
  423.    int planID=aiPlanCreate("Medium Axemen research at ten minutes.", cPlanResearch);
  424.    if (planID < 0)
  425.       return;
  426.  
  427.    aiPlanSetVariableInt(planID, cResearchPlanTechID, 0, cTechMediumAxemen);
  428.    aiPlanSetVariableInt(planID, cResearchPlanBuildingTypeID, 0, cUnitTypeBarracks);
  429.    aiPlanSetActive(planID);
  430.    
  431.     //Done.
  432.    xsDisableSelf();
  433. }
  434. */
  435.  
  436. //==============================================================================
  437. // Favor cheat 
  438. //==============================================================================
  439. rule favorCheat
  440.    minInterval 60
  441.    active
  442.    group AttackRules
  443. {
  444.     // Cheat for favor - 50 every minute
  445.     aiResourceCheat( 9, cResourceFavor, 50.0 );
  446. }
  447.  
  448.  
  449. //==============================================================================
  450. // Check the landing spot for unassigned dudes.
  451. //==============================================================================
  452. rule pollForMilitary       
  453.    minInterval 20
  454.    active
  455. {
  456.     vector landingBeach=kbGetBlockPosition("9953");
  457.     
  458.     int attackPlanSize = -1;
  459.     attackPlanSize = checkForMilitary(landingBeach);
  460.    if (attackPlanSize > 0)
  461.    {
  462.       aiEcho("P9 Attack Plan: Found "+attackPlanSize+" units on the beach.");
  463.         int newAttackPlanID=aiPlanCreate("Beach Attack", cPlanAttack);
  464.         if (newAttackPlanID >= 0)
  465.         {
  466.            //Target player.
  467.             aiPlanSetVariableInt(newAttackPlanID, cAttackPlanPlayerID, 0, 1);
  468.  
  469.            aiPlanSetVariableVector(newAttackPlanID, cAttackPlanGatherPoint, 0, landingBeach);
  470.            aiPlanSetVariableFloat(newAttackPlanID, cAttackPlanGatherDistance, 0, 40.0);
  471.  
  472.             //Add the unit(s).
  473.             aiPlanAddUnitType(newAttackPlanID, cUnitTypeAxeman, 0, 4, 4);
  474.             aiPlanAddUnitType(newAttackPlanID, cUnitTypeSpearman, 0, 4, 4);
  475.             aiPlanAddUnitType(newAttackPlanID, cUnitTypeScarab, 0, 1, 1);
  476.  
  477.             aiPlanSetNumberVariableValues(newAttackPlanID, cAttackPlanTargetTypeID, 2, true);
  478.  
  479.            //Unit types to attack.
  480.             aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 0, cUnitTypeBuilding);
  481.             aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 1, cUnitTypeUnit);
  482.  
  483.             aiPlanSetInitialPosition(newAttackPlanID, landingBeach);
  484.                         
  485.             //Setup the vars.
  486.             aiPlanSetDesiredPriority(newAttackPlanID, 40);
  487.             aiPlanSetActive(newAttackPlanID);
  488.  
  489.             //Save this off and orphan the previous attack.
  490.             aiPlanSetOrphan(attackPlan1ID, true);
  491.             attackPlan1ID=newAttackPlanID;
  492.         }
  493.    }
  494. }
  495.  
  496. //==============================================================================
  497. // MAIN.
  498. //==============================================================================
  499. void main(void)
  500. {
  501.     //Startup.
  502.    miscStartup();
  503.  
  504.    //Gather points 
  505.    vector gatherPointAxemen=kbGetBlockPosition("9956");
  506.     vector gatherPointSpearmen=kbGetBlockPosition("9955");
  507.     vector gatherPointScarab=kbGetBlockPosition("9954");
  508.  
  509.    //Create a simple plan to maintain 4 axemen.
  510.    int maintainPlan1ID=aiPlanCreate("Maintain 4 "+kbGetProtoUnitName(attackerUnitTypeIDSoldier1), cPlanTrain);
  511.    if (maintainPlan1ID >= 0)
  512.    {
  513.         //Must set the type of unit to train.
  514.       aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanUnitType, 0, attackerUnitTypeIDSoldier1);
  515.       //You can limit the number of units that are ever trained by this plan with this call.
  516.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  517.       //Set the number of units to maintain in the world at one time.
  518.       aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanNumberToMaintain, 0, 4);
  519.       //Train units quickly, to ensure we have enough.
  520.       aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanFrequency, 0, 10);
  521.       //Turn off training from multiple buildings.
  522.       //aiPlanSetVariableBool(maintainPlanID, cTrainPlanUseMultipleBuildings, 0, false);
  523.       //Set a gather target ID.
  524.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanGatherTargetID, 0, 1234);
  525.       //Set a gather point.
  526.       aiPlanSetVariableVector(maintainPlan1ID, cTrainPlanGatherPoint, 0, gatherPointAxemen);
  527.       //Activate the plan.
  528.       aiPlanSetActive(maintainPlan1ID);
  529.    }
  530.  
  531.     //Create a simple plan to maintain 4 spearmen.
  532.     int maintainPlan2ID=aiPlanCreate("Maintain 4 "+kbGetProtoUnitName(attackerUnitTypeIDSoldier2), cPlanTrain);
  533.    if (maintainPlan2ID >= 0)
  534.    {
  535.         //Must set the type of unit to train.
  536.       aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanUnitType, 0, attackerUnitTypeIDSoldier2);
  537.       //You can limit the number of units that are ever trained by this plan with this call.
  538.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  539.       //Set the number of units to maintain in the world at one time.
  540.       aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanNumberToMaintain, 0, 4);
  541.       //Train units quickly, to ensure we have enough.
  542.       aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanFrequency, 0, 10);
  543.       //Turn off training from multiple buildings.
  544.       //aiPlanSetVariableBool(maintainPlanID, cTrainPlanUseMultipleBuildings, 0, false);
  545.       //Set a gather target ID.
  546.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanGatherTargetID, 0, 1234);
  547.       //Set a gather point.
  548.       aiPlanSetVariableVector(maintainPlan2ID, cTrainPlanGatherPoint, 0, gatherPointSpearmen);
  549.       //Activate the plan.
  550.       aiPlanSetActive(maintainPlan2ID);
  551.    }
  552.  
  553.     //Create a simple plan to maintain 1 scarab.
  554.     int maintainPlan3ID=aiPlanCreate("Maintain 1 "+kbGetProtoUnitName(attackerUnitTypeIDMyth), cPlanTrain);
  555.    if (maintainPlan3ID >= 0)
  556.    {
  557.         //Must set the type of unit to train.
  558.       aiPlanSetVariableInt(maintainPlan3ID, cTrainPlanUnitType, 0, attackerUnitTypeIDMyth);
  559.       //You can limit the number of units that are ever trained by this plan with this call.
  560.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  561.       //Set the number of units to maintain in the world at one time.
  562.       aiPlanSetVariableInt(maintainPlan3ID, cTrainPlanNumberToMaintain, 0, 1);
  563.       //Train units quickly, to ensure we have enough.
  564.       aiPlanSetVariableInt(maintainPlan3ID, cTrainPlanFrequency, 0, 10);
  565.       //Turn off training from multiple buildings.
  566.       //aiPlanSetVariableBool(maintainPlanID, cTrainPlanUseMultipleBuildings, 0, false);
  567.       //Set a gather target ID.
  568.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanGatherTargetID, 0, 1234);
  569.       //Set a gather point.
  570.       aiPlanSetVariableVector(maintainPlan3ID, cTrainPlanGatherPoint, 0, gatherPointScarab);
  571.       //Activate the plan.
  572.       aiPlanSetActive(maintainPlan3ID);
  573.    }
  574. }
  575.